package org.lilei;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author lilei
 * @date 2020-04-03
 */
public class RpcServer implements ApplicationContextAware, InitializingBean {
    private static final Executor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors(),
            60L,
            TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors()),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
    );
    private Map<String, Object> handlerMap = new HashMap<>();
    private final int port;

    public RpcServer(int port) {
        this.port = port;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            while (true) {
                Socket socket = serverSocket.accept();
                executor.execute(new ProcessorHandler(handlerMap, socket));
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(RpcService.class);
        for (Object serviceBean : beanMap.values()) {
            String rpcService = serviceBean.getClass().getAnnotation(RpcService.class).value().getName();
            handlerMap.put(rpcService,serviceBean);
        }
    }
}
